From 06abbf369ff869a6ebb1cd4f195e3665505680c6 Mon Sep 17 00:00:00 2001 From: oliskoli Date: Mon, 12 Mar 2007 22:29:12 +0000 Subject: [PATCH] Check in nearly new gdb module. --- garmin_fs.h | 11 +- gdb.c | 2668 +++++++++++------------ xmldoc/formats/options/gdb-roadbook.xml | 19 + 3 files changed, 1244 insertions(+), 1454 deletions(-) create mode 100644 xmldoc/formats/options/gdb-roadbook.xml diff --git a/garmin_fs.h b/garmin_fs.h index f12a11a8e..7fb36f476 100644 --- a/garmin_fs.h +++ b/garmin_fs.h @@ -45,6 +45,9 @@ /* GMSD_SET(a,b): a = numeric gmsd field, b = numeric source */ #define GMSD_SET(a,b) if (gmsd) {gmsd->a = (b); gmsd->flags.a = 1; } +/* GMSD_UNSET(a): a = gmsd field */ +#define GMSD_UNSET(a) if (gmsd) { gmsd->flags.a = 0; } + /* GMSD_SETSTR(a,b): a = gmsd field, b = null terminated source */ #define GMSD_SETSTR(a,b) if (gmsd && (b) && (b)[0]) { gmsd->a = xstrdup((b)); gmsd->flags.a = 1; } @@ -56,7 +59,7 @@ typedef struct garmin_ilink_s { int ref_count; - double lat, lon; + double lat, lon, alt; struct garmin_ilink_s *next; } garmin_ilink_t; @@ -74,6 +77,9 @@ typedef struct { unsigned int cc:1; unsigned int cross_road:1; unsigned int addr:1; +#ifdef GMSD_EXPERIMENTAL + unsigned int subclass:1; +#endif } garmin_fs_flags_t; typedef struct garmin_fs_s @@ -97,6 +103,9 @@ typedef struct garmin_fs_s char *cross_road; /* Intersection road label */ char *addr; /* address + number */ garmin_ilink_t *ilinks; +#ifdef GMSD_EXPERIMENTAL + char subclass[22]; +#endif } garmin_fs_t, *garmin_fs_p; garmin_fs_t *garmin_fs_alloc(const int protocol); diff --git a/gdb.c b/gdb.c index 94a439138..76846141b 100644 --- a/gdb.c +++ b/gdb.c @@ -1,7 +1,7 @@ -/* +/* Garmin GPS Database Reader/Writer - Copyright (C) 2005-2007 Olaf Klein, o.b.klein@gpsbabel.org + Copyright (C) 2005,2006,2007 Olaf Klein, o.b.klein@gpsbabel.org Mainly based on mapsource.c, Copyright (C) 2005 Robert Lipe, robertlipe@usa.net @@ -53,6 +53,7 @@ 2006/11/01: Use version of GPSBabel and date/time of gdb.c (managed by CVS) for watermark 2007/01/23: add support for GDB version 3 2007/02/07: Add special code for unknown bytes in waypoints with class GE 8 (calculated points) + 2007/02/15: Nearly full rewrite. Full support for GDB V3. New option roadbook. */ #include @@ -61,1170 +62,997 @@ #include #include "defs.h" + +#include "cet.h" +#include "cet_util.h" +#include "garmin_fs.h" #include "garmin_tables.h" +#include "grtcirc.h" #include "jeeps/gpsmath.h" -#include "garmin_fs.h" -#include "cet_util.h" #define MYNAME "gdb" -#undef GDB_DEBUG +#define GDB_VER_1 1 +#define GDB_VER_2 2 +#define GDB_VER_3 3 -#define GDB_VER_MIN 1 -#define GDB_VER_MAX 2 +#define GDB_VER_UTF8 GDB_VER_3 +#define GDB_VER_MIN GDB_VER_1 +#define GDB_VER_MAX GDB_VER_3 -#define GDB_DEFAULTWPTCLASS 0 -#define GDB_HIDDENROUTEWPTCLASS 8 +#define GDB_DEF_CLASS gt_waypt_class_user_waypoint +#define GDB_DEF_HIDDEN_CLASS gt_waypt_class_map_point +#define GDB_DEF_ICON 18 #define GDB_NAME_BUFFERLEN 1024 -#define GDB_URL_BUFFERLEN 4096 /* Safety first */ -#define GDB_NOTES_BUFFERLEN 4096 /* (likewise) */ -#define DEFAULTICONVALUE 18 +#define GDB_DBG_WPT 1 +#define GDB_DBG_RTE 2 +#define GDB_DBG_TRK 4 -#ifdef UTF8_SUPPORT -# define GDB_UTF8_ENABLED 1 -#else -# define GDB_UTF8_ENABLED 0 -#endif +#define GDB_DBG_WPTe 8 +#define GDB_DBG_RTEe 16 +#define GDB_DBG_TRKe 32 -/* %%% local vars %%% */ +#define GDB_DEBUG (GDB_DBG_WPT | GDB_DBG_RTE) +#undef GDB_DEBUG -/* static char gdb_release[] = "$Revision: 1.49 $"; */ -static char gdb_release_date[] = "$Date: 2007/03/10 23:36:14 $"; +#define DBG(a,b) if ((GDB_DEBUG & (a)) && (b)) -static FILE *fin, *fout; -static char *fin_name, *fout_name; +/*******************************************************************************/ -static int gdb_ver = 1; -static int gdb_debug = 0; -static int gdb_via; /* 0 = read and write hidden points too; 1 = drop */ -static int gdb_category; +/* static char gdb_release[] = "$Revision: 1.50 $"; */ +static char gdb_release_date[] = "$Date: 2007/03/12 22:29:12 $"; -static queue gdb_hidden; -static short_handle gdb_short_handle; +static gbfile *fin, *fout; +static int gdb_ver, gdb_category, gdb_via, gdb_roadbook; -#define GDB_OPT_VER "ver" -#define GDB_OPT_VIA "via" -#define GDB_OPT_CATEGORY "cat" +static queue wayptq_in, wayptq_out, wayptq_in_hidden; +static short_handle short_h; -static char *gdb_opt_category = NULL; -static char *gdb_opt_ver = NULL; -static char *gdb_opt_via = NULL; +static char *gdb_opt_category; +static char *gdb_opt_ver; +static char *gdb_opt_via; +static char *gdb_opt_roadbook; -static arglist_t gdb_args[] = { - {GDB_OPT_CATEGORY, &gdb_opt_category, - "Default category on output (1..16)", NULL, ARGTYPE_INT, "1", "16"}, - {GDB_OPT_VER, &gdb_opt_ver, - "Version of gdb file to generate (1,2)", "2", ARGTYPE_INT, "1", "2"}, - {GDB_OPT_VIA, &gdb_opt_via, - "Drop route points that do not have an equivalent waypoint (hidden points)", NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, - ARG_TERMINATOR -}; +static int waypt_flag; +static int route_flag; + +static int waypt_ct; /* informational: total number of waypoints in/out */ +static int waypth_ct; /* informational: total number of hidden waypoints in/out */ +static int rtept_ct; /* informational: total number of route points in/out */ +static int trkpt_ct; /* informational: total number of track points in/out */ +static int rte_ct; /* informational: total number of routes in/out */ +static int trk_ct; /* informational: total number of tracks in/out */ -/********************************************************************************************************/ +/*******************************************************************************/ -/* %%% 1-1 functions from mapsource, should by shared!!! %%% */ +#define ELEMENTS(a) a->rte_waypt_ct +#define NOT_EMPTY(a) (a && *a) -static waypoint * -gdb_find_wpt_q_by_name(const queue *whichQueue, const char *name) +static void +gdb_flush_waypt_queue(queue *Q) { queue *elem, *tmp; - waypoint *waypointp; - QUEUE_FOR_EACH(whichQueue, elem, tmp) { - waypointp = (waypoint *) elem; - if (0 == case_ignore_strcmp(waypointp->shortname, name)) { - return waypointp; - } + QUEUE_FOR_EACH(Q, elem, tmp) { + waypoint *wpt = (waypoint *)elem; + dequeue(elem); + if (wpt->extra_data) + xfree(wpt->extra_data); + waypt_free(wpt); } - return NULL; } -static int -gdb_detect_rtept_class(const waypoint *wpt) + +#if GDB_DEBUG +static void +disp_summary(const gbfile *f) { - if (gdb_find_wpt_q_by_name((queue *)&gdb_hidden, wpt->shortname) == NULL) - return (int)GDB_HIDDENROUTEWPTCLASS; - else - return (int)GDB_DEFAULTWPTCLASS; -} + int i, len; + + len = strlen(f->name); + + warning(MYNAME ": ====================="); + for (i = 0; i < len; i++) warning("="); + warning("\n" MYNAME ": %s summary for \"%s\"\n", + (f->mode == 'r') ? "Reader" : "Writer", f->name); + warning(MYNAME ": ---------------------"); + for (i = 0; i < len; i++) warning("-"); -/* %%% local functions (read support) %%% */ + warning("\n" MYNAME ": %d waypoint(s)\n", waypt_ct - waypth_ct); + warning(MYNAME ": %d hidden waypoint(s)\n", waypth_ct); + warning(MYNAME ": %d route(s) with total %d point(s)\n", rte_ct, rtept_ct); + warning(MYNAME ": %d track(s) with total %d point(s)\n", trk_ct, trkpt_ct); + warning(MYNAME ": ---------------------"); -#ifdef GDB_DEBUG -static void -gdb_print_buff(const char *buff, int count, const char *comment) -{ - int i; - printf(MYNAME ": dump of %s : ", comment); - for (i = 0; i < count; i++) - { - printf("%02x ", buff[i] & 0xFF); - } - printf("\n"); - fflush(stdout); + for (i = 0; i < len; i++) warning("-"); + warning("\n"); } +#else +#define disp_summary(a) #endif -static waypoint * -gdb_create_rte_wpt(const char *name, double lat, double lon, double alt) +/*******************************************************************************/ +/* TOOLS AND MACROS FOR THE READER */ +/*-----------------------------------------------------------------------------*/ + +#define FREAD_C gbfgetc(fin) +#define FREAD(a,b) gbfread(a,(b),1,fin) +#define FREAD_i32 gbfgetint32(fin) +#define FREAD_i16 gbfgetint16(fin) +#define FREAD_STR(a) gdb_fread_str(a,sizeof(a),fin) +#define FREAD_CSTR gdb_fread_cstr(fin) +#define FREAD_DBL gbfgetdbl(fin) +#define FREAD_LATLON GPS_Math_Semi_To_Deg(gbfgetint32(fin)) + +#if GDB_DEBUG +static char * +nice(const char *str) { - waypoint *wpt; + char *res, *env; + cet_cs_vec_t *vec; - wpt = find_waypt_by_name(name); - if (wpt == NULL) - { - if (gdb_via != 0) return NULL; - wpt = gdb_find_wpt_q_by_name((queue *)&gdb_hidden, name); - } - if (wpt != NULL) - { - wpt = waypt_dupe(wpt); -// wpt->creation_time = 0; /* !!! should be removed !!! */ - } - else - { - wpt = waypt_new(); - wpt->shortname = xstrdup(name); - wpt->latitude = lat; - wpt->longitude = lon; - wpt->altitude = alt; - wpt->depth = unknown_alt; + if (!(str && *str)) return ""; + + env = getenv("LANG"); + if (env == NULL) return (char *)str; + + if ((res = strchr(env, '.'))) env = ++res; + vec = cet_find_cs_by_name(env); + + if ((vec != NULL) && (vec != global_opts.charset)) { + static char buf[128]; + res = cet_str_any_to_any(str, global_opts.charset, vec); + strncpy(buf, res, sizeof(buf)); + xfree(res); + return buf; } - return wpt; + else return (char *)str; } +#endif -static size_t -gdb_fread(void *target, size_t size) +static char * +gdb_fread_cstr(gbfile *fin) { - size_t result; - - result = fread(target, 1, size, fin); - if (result < size) - { - if (feof(fin) != 0) - fatal(MYNAME ": unexpected end of file \"%s\"!\n", fin_name); - else - fatal(MYNAME ": I/O error occured during read from \"%s\"!\n", fin_name); + char *result = gbfgetcstr(fin); + + if (result && (*result == '\0')) { + xfree(result); + result = NULL; } return result; } static int -gdb_fread_str(char *dest, size_t maxlen) +gdb_fread_str(char *buf, int size, gbfile *fin) { - int c; + char c; int res = 0; - while (maxlen-- > 0) - { - c = fgetc(fin); - if ( c != EOF ) - { - if (c < 0) - fatal(MYNAME ": I/O error (%d) while read from \"%s\"!\n", +c, fin_name); - *dest++ = c; - if ( c == 0 ) return res; + while (size--) { + gbfread(&c, 1, 1, fin); + buf[res] = c; + if (c == '\0') return res; res++; - } - else - { - *dest++ = '\0'; - return res; - } } - fatal(MYNAME ": local buffer overflow detected, please report!\n"); - return 0; + buf[res] = '\0'; + return res; } -static int -gdb_fread_le(void *dest, size_t size, const unsigned int bit_count, const char *prefix, const char *field) +static char * +gdb_fread_strlist(void) { - char buff[32]; - unsigned char *c = dest; - short *sh = dest; - int *li = dest; - double *db = dest; - - if ((bit_count >> 3) != size) - fatal(MYNAME "%s: Internal error (gdb_le_read/%d/%d/%s)!\n", prefix, (int)size, bit_count >> 3, field); - - switch(bit_count) - { - case 8: - gdb_fread(c, sizeof(*c)); - if (gdb_debug) - printf(MYNAME "%s: gdb_fread_le : %d -> %s (0x%x))\n", prefix, *c, field, *c); - return *c; - case 16: - if (sizeof(*sh) != size) fatal(MYNAME ": internal decl.!\n"); - gdb_fread(sh, sizeof(*sh)); - *sh = le_read16(sh); - if (gdb_debug) - printf(MYNAME "%s: gdb_fread_le : %d -> %s (0x%x))\n", prefix, *sh, field, *sh); - return *sh; - case 32: - gdb_fread(li, 4); - *li = le_read32(li); - if (gdb_debug) - printf(MYNAME "%s: gdb_fread_le : %d -> %s (0x%x)\n", prefix, *li, field, *li); - return *li; - case 64: - gdb_fread(buff, sizeof(*db)); - le_read64(db, buff); - if (gdb_debug) - printf(MYNAME "%s: gdb_fread_le : %g -> %s\n", prefix, *db, field); - return 0; - default: - fatal(MYNAME "%s: unsupported bit count (%d) in gdb_le_read!\n", prefix, bit_count); + char *res = NULL; + int count; + + count = FREAD_i32; + + while (count > 0) { + char *str = FREAD_CSTR; + if (str != NULL) { + if (*str && (res == NULL)) res = str; + else xfree(str); + } + count--; } - return 0; + + return res; } -static int -gdb_fread_flag(const char value) /* read one byte and compare to value */ +static waypoint * +gdb_find_wayptq(const queue *Q, const waypoint *wpt, const char exact) { - char c; + queue *elem, *tmp; + const char *name = wpt->shortname; + + QUEUE_FOR_EACH(Q, elem, tmp) { + waypoint *tmp = (waypoint *)elem; + if (case_ignore_strcmp(name, tmp->shortname) == 0) { + if (! exact) return tmp; + if ((tmp->latitude == wpt->latitude) && + (tmp->longitude == wpt->longitude)) + return tmp; + } + } + return NULL; +} + +static waypoint * +gdb_reader_find_waypt(const waypoint *wpt, const char exact) +{ + waypoint *res; + res = gdb_find_wayptq(&wayptq_in, wpt, exact); + if (res == NULL) + res = gdb_find_wayptq(&wayptq_in_hidden, wpt, exact); + return res; +} - gdb_fread(&c, 1); - return (c == value); +static waypoint * +gdb_add_route_waypt(route_head *rte, waypoint *ref, const int wpt_class) +{ + waypoint *tmp, *res; + int turn_point; + + tmp = gdb_reader_find_waypt(ref, 1); + if (tmp == NULL) { + double dist; + + tmp = find_waypt_by_name(ref->shortname); + if (tmp == NULL) { + route_add_wpt(rte, ref); + return ref; + } + + /* At this point we have found a waypoint with same name, + but probably from another data stream. Check coordinates! + */ + dist = radtometers(gcdist( + RAD(ref->latitude), RAD(ref->longitude), + RAD(tmp->latitude), RAD(tmp->longitude))); + + if (fabs(dist) > 100) { + warning(MYNAME ": Route point mismatch!\n"); + warning(MYNAME ": \"%s\" from waypoints differs to \"%s\"\n", + tmp->shortname, ref->shortname); + fatal(MYNAME ": from route table by more than %0.1f meters!\n", + dist); + + } + } + res = NULL; + turn_point = (gdb_roadbook && (wpt_class > gt_waypt_class_map_point) && tmp->description); + if (turn_point || (gdb_via == 0) || (wpt_class == 0)) { + res = waypt_dupe(tmp); + route_add_wpt(rte, res); + } + waypt_free(ref); + return res; } +/*******************************************************************************/ +/* TOOLS AND MACROS FOR THE WRITER */ +/*-----------------------------------------------------------------------------*/ + +#define FWRITE_CSTR(a) ((a) == NULL) ? gbfputc(0,fout) : gbfputcstr((a),fout) +#define FWRITE_i16(a) gbfputint16((a),fout) +#define FWRITE_i32(a) gbfputint32((a),fout) +#define FWRITE(a, b) gbfwrite(a,(b),1,fout) +#define FWRITE_C(a) gbfputc((a),fout) +#define FWRITE_DBL(a,b) gdb_write_dbl((a),(b)) +#define FWRITE_TIME(a) gdb_write_time((a)) +#define FWRITE_CSTR_LIST(a) gdb_write_cstr_list((a)) +#define FWRITE_LATLON(a) gbfputint32(GPS_Math_Deg_To_Semi((a)),fout) + static void -gdb_is_valid(int is, const char *prefix, const char *comment) +gdb_write_cstr_list(const char *str) { - if (is == 0) - { - printf(MYNAME ": Reading database \"%s\"\n", fin_name); - fatal(MYNAME "-%s: Found error in data (%s)!\n", prefix, comment); + if NOT_EMPTY(str) { + gbfputint32(1, fout); + gbfputcstr(str, fout); + } else + gbfputint32(0, fout); +} + +static void +gdb_write_dbl(const double value, const double def) +{ + if (value == def) gbfputc(0, fout); + else { + gbfputc(1, fout); + gbfputdbl(value, fout); } } static void -gdb_is_validf(int is, const char *prefix, const char *format, ...) +gdb_write_time(const int time) { - va_list args; - - if (is != 0) return; - - va_start(args, format); - if (fin_name != NULL) - printf(MYNAME "-%s: Reading from database \"%s\"\n", prefix, fin_name); + if (time > 0) { + gbfputc(1, fout); + gbfputint32(time, fout); + } else - printf(MYNAME "-%s: Writing to database \"%s\"\n", prefix, fout_name); - printf(MYNAME "-%s: ", prefix); - vprintf(format, args); - va_end(args); - - fatal("\n"); + gbfputc(0, fout); } -/********************************************************************************************************/ -/* %%% read file header */ -/********************************************************************************************************/ +/*******************************************************************************/ +/* GDB "Garmin Database" READER CODE */ +/*-----------------------------------------------------------------------------*/ static void -gdb_read_file_header(void) +read_file_header(void) { - char buff[128]; + char buf[128]; int i, reclen; - - const char *prefix = "read_head"; + /* - We starts with standard binary read. - A gdb_fread_str works too, but if we get a wrong file as input, + We are beginning with a simple binary read. +*/ + FREAD(buf, 6); +/* + A "gbfgetcstr" (FREAD_CSTR) works too, but if we get a wrong file as input, the file validation my be comes too late. For example a XML base file normally has no binary zeros inside and produce, if big enought, a buffer overflow. The following message "local buffer overflow detected..." could be misinterpreted. */ - - if (6 != fread(buff, 1, 6, fin)) - fatal(MYNAME ": Invalid file \"%s\"!\n", fin_name); + is_fatal(strcmp(buf, "MsRcf") != 0, MYNAME ": Invalid file \"%s\"!", fin->name); - if (strcmp(buff, "MsRcf") != 0) - fatal(MYNAME ": Invalid file \"%s\"!\n", fin_name); - - gdb_fread(&reclen, 4); - reclen = le_read32(&reclen); - - gdb_is_valid(reclen == gdb_fread_str(buff, sizeof(buff)), prefix, "Invalid record length"); - if (buff[0] != 'D') - fatal(MYNAME ": Invalid file \"%s\"!\n", fin_name); + reclen = FREAD_i32; + i = FREAD_STR(buf); + is_fatal(buf[0] != 'D', MYNAME ": Invalid file \"%s\"!", fin->name); - switch(buff[1]) - { - case 'k': - gdb_ver = 1; - break; - case 'l': - gdb_ver = 2; - break; - case 'm': - gdb_ver = 3; - break; - default: - fatal(MYNAME ": Non supported GDB version!\n"); - } + gdb_ver = buf[1] - 'k' + 1; + is_fatal((gdb_ver < GDB_VER_MIN) || (gdb_ver > GDB_VER_MAX), + MYNAME ": Unknown or/and unsupported GDB version (%d.0)!", gdb_ver); if (global_opts.verbose_status > 0) - printf(MYNAME ": Found Garmin GPS Database version %d.0\n", gdb_ver); - - gdb_fread(&reclen, 4); - reclen = le_read32(&reclen); - gdb_is_valid(reclen < (int)sizeof(buff), prefix, "Invalid record length"); - gdb_fread(buff, reclen); - - gdb_is_valid(0 == gdb_fread_str(buff, sizeof(buff)), prefix, "header"); - - i = gdb_fread_str(buff, sizeof(buff)); - gdb_is_valid((i == 9) && (strcmp(buff, "MapSource") == 0), prefix, "MapSource magic"); + printf(MYNAME ": Reading Garmin GPS Database version %d.0\n", gdb_ver); + + reclen = FREAD_i32; + i = FREAD(buf, reclen + 1); + if (global_opts.verbose_status >= 0) { + char *name = buf+2; + if (strstr(name, "SQA") == 0) name = "MapSource"; + else if (strstr(name, "neaderhi") == 0) name = "MapSource BETA"; + else warning(MYNAME ": Created with \"%s\"\n", name); + } + + i = FREAD_STR(buf); + is_fatal((i != 9) || (strcmp(buf, "MapSource") != 0), "Invalid header!"); } -/********************************************************************************************************/ -/* %%% read waypoint */ -/********************************************************************************************************/ +/*-----------------------------------------------------------------------------*/ static waypoint * -gdb_read_wpt(const size_t fileofs, int *wptclass) +read_waypoint(gt_waypt_classes_e *waypt_class_out) { - char xname[GDB_NAME_BUFFERLEN]; - char xnotes[GDB_NOTES_BUFFERLEN]; - char xurl[GDB_URL_BUFFERLEN]; - int xclass; - int xlat, xlon, xdisplay, xcolour, xicon, xtime, dynamic; - short xcat; - double xdepth = unknown_alt; - double xalt = unknown_alt; - double xproximity = unknown_alt; - double xtemp; + char buf[128]; /* used for temporary stuff */ + int wpt_class, display, icon, dynamic; + int i; waypoint *res; - char buff[128]; - size_t pos, delta; - garmin_fs_t *gmsd = NULL; - - const char *prefix = "wpt_read"; - + garmin_fs_t *gmsd; +#ifdef GMSD_EXPERIMENTAL + char subclass[22]; +#endif +#if GDB_DEBUG + char *sn; +#endif + waypt_ct++; res = waypt_new(); - + gmsd = garmin_fs_alloc(-1); fs_chain_add(&res->fs, (format_specific_data *) gmsd); - -/********************************************************************************************************/ -/* record structure - - zstring name - dword class - zstring country - 4 * 0x00 subclass part 1 - 12 * 0xFF subclass part 2 - 2 * 0x00 subclass part 3 - 4 * 0xFF unknown - dword latitude - dword longitude - if (1) +8 altitude = (1 or 9) - zstring comment - dword display flag - dword display colour - dword icon - zstring city ? - zstring state ? - zstring facility ? - char unknown ? - double depth (if flag) - zstring url - word category -> offset 79 - double temp (if flag) - */ -/********************************************************************************************************/ - - gdb_is_valid(gdb_fread_str(xname, sizeof(xname)) > 0, prefix, "new waypoint"); - res->shortname = xstrdup(xname); - - gdb_fread_le(&xclass, sizeof(xclass), 32, prefix, "class"); - GMSD_SET(wpt_class, xclass); - - gdb_fread_str(buff, sizeof(buff)); /* country code */ - GMSD_SETSTR(cc, buff); - - gdb_fread(buff, 22); - xlat = gdb_fread_le(&xlat, sizeof(xlat), 32, prefix, "latitude"); - xlon = gdb_fread_le(&xlon, sizeof(xlon), 32, prefix, "longitude"); - - if (gdb_fread_flag(1)) { /* altitude flag */ - gdb_fread_le(&xalt, sizeof(xalt), 64, prefix, "altitude"); - if (xalt > 1.0e24) - xalt = unknown_alt; + + res->shortname = FREAD_CSTR; +#if GDB_DEBUG + sn = xstrdup(nice(res->shortname)); +#endif + wpt_class = FREAD_i32; + GMSD_SET(wpt_class, wpt_class); + if (wpt_class != 0) waypth_ct++; + + FREAD_STR(buf); /* Country code */ + GMSD_SETSTR(cc, buf); + +#ifdef GMSD_EXPERIMENTAL + FREAD(subclass, sizeof(subclass)); + if (gmsd && (wpt_class >= gt_waypt_class_map_point)) { + memcpy(gmsd->subclass, subclass, sizeof(gmsd->subclass)); + gmsd->flags.subclass = 1; } - - gdb_fread_str(xnotes, sizeof(xnotes)); /* notes */ - - if (gdb_fread_flag(1)) { /* proximity flag */ - gdb_fread_le(&xproximity, sizeof(xproximity), 64, prefix, "proximity"); - GMSD_SET(proximity, xproximity); +#else + FREAD(buf, 22); +#endif + res->latitude = FREAD_LATLON; + res->longitude = FREAD_LATLON; + + if (FREAD_C == 1) { + double alt = gbfgetdbl(fin); + if (alt < 1.0e24) res->altitude = alt; } - - xdisplay = gdb_fread_le(&xdisplay, sizeof(xdisplay), 32, prefix, "display"); - switch(xdisplay) { - case gt_gdb_display_mode_symbol: - xdisplay = gt_display_mode_symbol; - break; +#if GDB_DEBUG + DBG(GDB_DBG_WPT, 1) + printf(MYNAME "-wpt \"%s\": coordinates = %c%0.6f %c%0.6f\n", + sn, + res->latitude < 0 ? 'S' : 'N', res->latitude, + res->longitude < 0 ? 'W' : 'E', res->longitude); +#endif + res->notes = FREAD_CSTR; +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, res->notes) + printf(MYNAME "-wpt \"%s\" (%d): notes = %s\n", + sn, wpt_class, nice(res->notes)); +#endif + if (FREAD_C == 1) { + double proximity = gbfgetdbl(fin); + GMSD_SET(proximity, proximity); + } + i = FREAD_i32; +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, 1) + printf(MYNAME "-wpt \"%s\" (%d): display = %d\n", + sn, wpt_class, i); +#endif + switch(i) { /* display value */ + case gt_gdb_display_mode_symbol: + display = gt_display_mode_symbol; break; case gt_gdb_display_mode_symbol_and_comment: - xdisplay = gt_display_mode_symbol_and_comment; - break; - default: /* gt_gdb_display_mode_symbol_and_name and others */ - xdisplay = gt_display_mode_symbol_and_name; - break; + display = gt_display_mode_symbol_and_comment; break; + default: + display = gt_display_mode_symbol_and_name; break; + } + GMSD_SET(display, display); + + FREAD_i32; /* color/colour !not implemented! */ + icon = FREAD_i32; + GMSD_SET(icon, icon); /* icon */ + FREAD_STR(buf); /* city */ + GMSD_SETSTR(city, buf); + FREAD_STR(buf); /* state */ + GMSD_SETSTR(state, buf); + FREAD_STR(buf); /* facility */ + GMSD_SETSTR(facility, buf); + + FREAD(buf, 1); + + if (FREAD_C == 1) { + double depth = gbfgetdbl(fin); + GMSD_SET(depth, depth); } - GMSD_SET(display, xdisplay); - - xcolour = gdb_fread_le(&xcolour, sizeof(xcolour), 32, prefix, "colour"); - xicon = gdb_fread_le(&xicon, sizeof(xicon), 32, prefix, "icon"); - GMSD_SET(icon, xicon); + FREAD(buf, 2); /* ?????????????????????????????????? */ - gdb_fread_str(buff, sizeof(buff)); /* city */ - GMSD_SETSTR(city, buff); + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + char *temp; + + waypt_flag = FREAD_C; + if (waypt_flag == 0) + FREAD(buf, 3); + else + FREAD(buf, 2); + + temp = FREAD_CSTR; /* undocumented & unused string */ +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, temp) + printf(MYNAME "-wpt \"%s\" (%d): Unknown string = %s\n", + sn, wpt_class, nice(temp)); +#endif + if (temp) xfree(temp); + + res->url = FREAD_CSTR; + if (wpt_class != 0) { + res->description = res->url; + res->url = NULL; + } + } + else { // if (gdb_ver >= GDB_VER_3) + int cnt; + + FREAD(buf, 4); /* ???? */ + waypt_flag = 0; + res->description = FREAD_CSTR; - gdb_fread_str(buff, sizeof(buff)); /* state */ - GMSD_SETSTR(state, buff); - - gdb_fread_str(buff, sizeof(buff)); /* facility */ - GMSD_SETSTR(facility, buff); - - gdb_fread(buff, 1); /* unknown */ - - if (gdb_fread_flag(1)) { /* depth flag */ - gdb_fread_le(&xdepth, sizeof(xdepth), 64, prefix, "depth"); - GMSD_SET(depth, xdepth); + for (cnt = FREAD_i32; cnt; cnt--) { + char *str = FREAD_CSTR; + if (str && *str) waypt_add_url(res, str, NULL); + } } - - if (gdb_ver >= 3) { - int url_ct, unkn; - char *url = NULL; - - unkn = gdb_fread_le(&unkn, sizeof(unkn), 32, prefix, "unknown dword(x) since v3"); - gdb_fread(buff, 2); - - gdb_fread_str(xurl, sizeof(xurl)); /* what dagmar will say */ - - url_ct = gdb_fread_le(&url_ct, sizeof(url_ct), 32, prefix, "number of urls (since v3)"); - gdb_is_valid((url_ct >= 0), prefix, "Number of urls (since v3)"); - - while (url_ct > 0) { - char v3xurl[GDB_URL_BUFFERLEN]; - url_ct--; - gdb_fread_str(v3xurl, sizeof(v3xurl)); /* URL list */ - add_url(res, xstrdup(v3xurl), NULL); -#if 0 - if ((url == NULL) && (xurl[0] != '\0')) - url = xstrdup(xurl); /* keep only the first valid entry */ + +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, res->description) + printf(MYNAME "-wpt \"%s\" (%d): description = %s\n", + sn, wpt_class, nice(res->description)); + DBG(GDB_DBG_WPTe, res->url) + printf(MYNAME "-wpt \"%s\" (%d): url = %s\n", + sn, wpt_class, nice(res->url)); +#endif + i = FREAD_i16; + if (i != 0) GMSD_SET(category, i); + + if (FREAD_C == 1) { + res->temperature = FREAD_DBL; +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, 1) + printf(MYNAME "-wpt \"%s\" (%d): temperature = %f\n", + sn, wpt_class, res->temperature); #endif - } - if (url != NULL) { - strncpy(xurl, url, sizeof(xurl)); - xfree(url); - } } - else { /* gdb_ver <= 2 */ - gdb_fread(buff, 2); - if (gdb_fread_flag(0)) - gdb_fread(buff, 3); - else - gdb_fread(buff, 2); - - do /* undocumented & unused string */ - { - gdb_fread(buff, 1); - } - while (buff[0] != 0); - - gdb_fread_str(xurl, sizeof(xurl)); /* URL */ + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + if (waypt_flag != 0) FREAD(buf, 1); } - - xcat = gdb_fread_le(&xcat, sizeof(xcat), 16, prefix, "category"); - if (xcat != 0) GMSD_SET(category, xcat); - - if (gdb_fread_flag(1)) { /* temperature flag */ - gdb_fread_le(&xtemp, sizeof(xtemp), 64, prefix, "temperature"); - GMSD_SET(temperature, xtemp); + if (FREAD_C == 1) { + res->creation_time = FREAD_i32; } - pos = ftell(fin); - delta = fileofs - pos; - gdb_is_valid((delta > 0), prefix, "waypoint final"); - - if (gdb_ver >= 3) { - delta--; - if (gdb_fread_flag(1)) { - gdb_is_valid((delta >= 4), prefix, "No waypoint time (v3++)"); - gdb_fread_le(&xtime, sizeof(xtime), 32, prefix, "time"); - gdb_is_valid((xtime > 0), prefix, "Invalid time (v3++)"); - delta-=sizeof(xtime); - } - else - xtime = 0; - if (delta > 0) { /* skip over trailing unknown bytes */ - gdb_is_valid((delta <= sizeof(buff)), prefix, "Waypoint structure V3"); - gdb_fread(buff, delta); - } + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_3) { + FREAD(buf, 6); /* ???? */ } - else { /* gdb_ver <= 2 */ - - /* Here comes 1 .. 6 unknown bytes - !!! 6 only if class > 0 !!! - the field seems to be a time stamp */ - - if ((delta & 1) == 0) { - delta--; - gdb_fread(buff, 1); - if (buff[0] != '\0') - warning(MYNAME ": Invalid byte (0x%02x) at EOW'.\n", (unsigned char)buff[0]); - } - - xtime = 0; - - delta--; - if (gdb_fread_flag(1)) { - gdb_is_valid((delta == 4), prefix, "Waypoint time"); - gdb_fread_le(&xtime, sizeof(xtime), 32, prefix, "time"); - } - else if (delta > 0) { - gdb_is_valid((delta <= sizeof(buff)), prefix, "Waypoint structure"); - gdb_fread(buff, delta); - if (xclass < gt_waypt_class_map_point) { - warning(MYNAME ": Unhandled EOW. Please report!\n"); - fatal(MYNAME ": [class is 0x%02xh, %d bytes left, gdb version %d]\n", - xclass, (int)delta, gdb_ver); - } - } - } - - *wptclass = xclass; - if (xurl[0] != '\0') - { - if (xclass == 0) - res->url = xstrdup(xurl); - else - res->description = xstrdup(xurl); - } - if (xnotes[0] != '\0') res->notes = xstrdup(xnotes); - res->latitude = GPS_Math_Semi_To_Deg(xlat); - res->longitude = GPS_Math_Semi_To_Deg(xlon); - res->altitude = xalt; - res->creation_time = xtime; - - /* might need to change this to handle version dependent icon handling */ - res->icon_descr = gt_find_desc_from_icon_number(xicon, GDB, &dynamic); + res->icon_descr = gt_find_desc_from_icon_number(icon, GDB, &dynamic); res->wpt_flags.icon_descr_is_dynamic = dynamic; - gdb_is_validf(fabs(res->latitude) <= 90.0, prefix, "%s has invalid latitude (%f)", - res->shortname, res->latitude); - +#if GDB_DEBUG + DBG(GDB_DBG_WPTe, icon != GDB_DEF_ICON) + printf(MYNAME "-wpt \"%s\" (%d): icon = \"%s\" (MapSoure %d)\n", + sn, wpt_class, nice(res->icon_descr), icon); +#endif + if (gdb_roadbook && (wpt_class > gt_waypt_class_map_point) && res->description) { + wpt_class = gt_waypt_class_user_waypoint; + GMSD_SET(wpt_class, wpt_class); +#ifdef GMSD_EXPERIMENTAL + GMSD_UNSET(subclass); +#endif + } +#if GDB_DEBUG + xfree(sn); +#endif + *waypt_class_out = wpt_class; return res; } -/********************************************************************************************************/ -/* %%% read route */ -/********************************************************************************************************/ +/*-----------------------------------------------------------------------------*/ static route_head * -gdb_read_route(void) +read_route(void) { - char xname[GDB_NAME_BUFFERLEN]; - char xwptname[GDB_NAME_BUFFERLEN]; - int xclass; - double xalt; - double xlat = 0; /* compiler warnings */ - double xlon = 0; /* compiler warnings */ - - char buff[256]; - int count, origin; - int isteps; - int semilat, semilon; - int maxlat, maxlon, minlon, minlat; - char auto_name; - - route_head *route; - waypoint *wpt; - - const char prefix[] = "rte_read_head"; - const char prefix1[] = "rte_read_loop"; - const char prefix2[] = "rte_ils_loop"; - const char prefix3[] = "rte_read_final"; - - gdb_is_valid(gdb_fread_str(xname, sizeof(xname)) > 0, prefix, "Route has no name"); - - gdb_fread_le(&auto_name, sizeof(auto_name), 8, prefix, "auto name"); - if (gdb_fread_flag(0)) /* max. data flag */ - { - gdb_fread_le(buff, 4, 32, prefix, "max. latitude"); - gdb_fread_le(buff, 4, 32, prefix, "max. longitude"); + route_head *rte; + int points, warnings, links, i; + char buf[128]; + bounds bounds; - gdb_fread(buff, 1); - if (buff[0] == 1) gdb_fread_le(buff, 8, 64, prefix, "max. altitude"); - - gdb_fread_le(buff, 4, 32, prefix, "min. latitude"); - gdb_fread_le(buff, 4, 32, prefix, "min. longitude"); + rte_ct++; + warnings = 0; - gdb_fread(buff, 1); - if (buff[0] == 1) - gdb_fread_le(buff, 8, 64, prefix, "min. altitude"); + rte = route_head_alloc(); +// rte->rte_num = rte_ct; + rte->rte_name = FREAD_CSTR; + FREAD(buf, 1); /* display/autoname - 1 byte */ + + if (FREAD_C == 0) { /* max. data flag */ + /* maxlat = */ FREAD_i32; + /* maxlon = */ FREAD_i32; + if (FREAD_C == 1) /* maxalt = */ gbfgetdbl(fin); + /* minlat = */ FREAD_i32; + /* minlon = */ FREAD_i32; + if (FREAD_C == 1) /* minalt = */ gbfgetdbl(fin); } - - gdb_fread_le(&count, sizeof(count), 32, prefix, "count"); - if (count == 0) - fatal(MYNAME "%s: !!! Empty routes are not allowed !!!\n", prefix); - - route = route_head_alloc(); - route->rte_name = xstrdup(xname); - route_add_head(route); - - origin = count; - - while (count--) - { - garmin_fs_t *gmsd = NULL; - garmin_ilink_t *anchor; - - gdb_fread_str(xwptname, sizeof(xwptname)); /* waypoint name */ + links = 0; + points = FREAD_i32; - gdb_fread_le(&xclass, sizeof(xclass), 32, prefix1, "class"); /* class */ - gdb_fread_str(buff, sizeof(buff)); /* country */ - - gdb_fread(buff, 22); /* sub class data */ - gdb_fread(buff, 1); - if (buff[0] != 0) { /* 0x00 or 0xFF */ - gdb_fread(buff, 8); /* unknown 8 bytes */ -#ifdef GDB_DEBUG - gdb_print_buff(buff, 8, "Unknown bytes within rte_reed_loop"); +#if GDB_DEBUG + DBG(GDB_DBG_RTE, 1) + printf(MYNAME "-rte \"%s\": loading route with %d point(s)...\n", + nice(rte->rte_name), points); #endif - if (gdb_ver >= 3) - gdb_fread(buff, 8); /* a second block of unknown bytes */ - } - /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */ - /* OK: this should be, but i've seen exceptions (...cannot verify the first byte */ - gdb_fread(buff, 18); + for (i = 0; i < points; i++) { + int wpt_class, j; + char buf[128]; + garmin_ilink_t *il_root, *il_anchor; - gdb_fread_le(&isteps, sizeof(isteps), 32, prefix1, "interlink steps"); - - if (isteps <= 0) /* ??? end of route or error ??? */ - { - gdb_is_valid(count == 0, prefix3, "Zero interlink steps within route"); - - gdb_fread(buff, 1); - gdb_is_valid((buff[0] == 1), prefix3, "last seq.(1)"); + waypoint *wpt; - if (gdb_ver >= 2) - gdb_fread(buff, 8); /* Unknown 8 bytes since gdb v2 */ + wpt = waypt_new(); + rtept_ct++; + + wpt->shortname = FREAD_CSTR; /* shortname */ + wpt_class = FREAD_i32; /* waypoint class */ + FREAD_STR(buf); /* country code */ + FREAD(buf, 18 + 4); /* subclass part 1-3 / unknown */ + + if (FREAD_C != 0) { + FREAD(buf, 8); /* aviation data (?); only seen with class "1" (Airport) */ + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_3) + FREAD(buf, 8); /* a second block since V3 */ + } - gdb_fread_str(xname, sizeof(xname)); - if (xname[0] != 0) - route->rte_url = xstrdup(xname); + FREAD(buf, 18); /* unknown 18 bytes; but first should be 0x01 or 0x03 */ + if ((buf[0] != 0x01) && (buf[0] != 0x03)) { + int i; + + warnings++; + if (warnings > 3) + fatal(MYNAME "-rte_pt \"%s\": too many warnings!\n", wpt->shortname); + warning(MYNAME "-rte_pt \"%s\" (class %d): possible error in route.\n", wpt->shortname, wpt_class); + warning(MYNAME "-rte_pt (dump):"); + for (i = 0; i < 18; i++) { + warning(" %02x", (unsigned char)buf[i]); + } + warning("\n"); + } - if (gdb_ver >= 3) { - - int url_ct, unkn; - - gdb_fread(buff, 1); /* Unknown byte since gdb v3 */ - gdb_fread_le(&url_ct, sizeof(url_ct), 32, prefix3, "number of urls (since v3)"); - while (url_ct > 0) { - url_ct--; - gdb_fread_str(xname, sizeof(xname)); - if (route->rte_url == NULL) - route->rte_url = xstrdup(xname); - } - gdb_fread_le(&unkn, sizeof(unkn), 32, prefix3, "unknown dword (since v3)"); - gdb_fread(buff, 1); /* Unknown byte since gdb v3 */ - gdb_fread_str(xname, sizeof(xname)); /* multi-line notes */ - if (xname[0] != '\0') - route->rte_desc = xstrdup(xname); + links = FREAD_i32; + il_anchor = NULL; + il_root = NULL; +#if GDB_DEBUG + DBG(GDB_DBG_RTE, 1) + printf(MYNAME "-rte_pt \"%s\" (%d): %d interlink step(s)\n", + nice(wpt->shortname), wpt_class, links); +#endif + for (j = 0; j < links; j++) { + garmin_ilink_t *il_step = xmalloc(sizeof(*il_step)); + + il_step->ref_count = 1; + + il_step->lat = FREAD_LATLON; + il_step->lon = FREAD_LATLON; + if (FREAD_C == 1) il_step->alt = FREAD_DBL; + else il_step->alt = unknown_alt; + + if (j == 0) { + wpt->latitude = il_step->lat; + wpt->longitude = il_step->lon; + wpt->altitude = il_step->alt; + } + + il_step->next = NULL; + if (il_anchor == NULL) + il_root = il_step; + else + il_anchor->next = il_step; + il_anchor = il_step; + +#if GDB_DEBUG + DBG(GDB_DBG_RTEe, 1) { + printf(MYNAME "-rte_il \"%s\" (%d of %d): %c%0.6f %c%0.6f\n", + nice(wpt->shortname), j + 1, links, + il_step->lat < 0 ? 'S' : 'N', il_step->lat, + il_step->lon < 0 ? 'W' : 'E', il_step->lon); + } +#endif } - wpt = gdb_create_rte_wpt(xwptname, xlat, xlon, xalt); - if (wpt != NULL) - route_add_wpt(route, wpt); - return route; - } - - gdb_fread_le(&semilat, sizeof(semilat), 32, prefix1, "semi-latitude"); - gdb_fread_le(&semilon, sizeof(semilon), 32, prefix1, "semi-longitude"); - xlat = GPS_Math_Semi_To_Deg(semilat); - xlon = GPS_Math_Semi_To_Deg(semilon); - - gdb_is_validf(fabs(xlat) <= 90.0, prefix1, "Invalid latitude (%f)", xlat); - - if (gdb_fread_flag(1)) /* altitude flag */ - gdb_fread_le(&xalt, sizeof(xalt), 64, prefix1, "altitude"); - else - xalt = unknown_alt; - - wpt = gdb_create_rte_wpt(xwptname, xlat, xlon, xalt); - if (wpt != NULL) { - route_add_wpt(route, wpt); - gmsd = GMSD_FIND(wpt); - if (gmsd == NULL) { - gmsd = garmin_fs_alloc(-1); - fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + + waypt_init_bounds(&bounds); + + if (FREAD_C == 0) { /* interlink bounds */ + bounds.max_lat = FREAD_LATLON; + bounds.max_lon = FREAD_LATLON; + if (FREAD_C == 1) + bounds.max_alt = FREAD_DBL; + bounds.min_lat = FREAD_LATLON; + bounds.min_lat = FREAD_LATLON; + if (FREAD_C == 1) + bounds.min_alt = FREAD_DBL; } - GMSD_SET(wpt_class, xclass); - } - else { - gmsd = NULL; - } - - anchor = NULL; - - while (--isteps > 0) - { - gdb_fread_le(&semilat, sizeof(semilat), 32, prefix2, "semi-latitude"); - gdb_fread_le(&semilon, sizeof(semilon), 32, prefix2, "semi-longitude"); - gdb_fread(buff, 1); /* altitude flag */ - if (buff[0] == 1) - gdb_fread_le(&xalt, sizeof(xalt), 64, prefix2, "altitude"); - - xlat = GPS_Math_Semi_To_Deg(semilat); - xlon = GPS_Math_Semi_To_Deg(semilon); - gdb_is_validf(fabs(xlat) <= 90.0, prefix2, "Invalid latitude (%f)", xlat); - if (gmsd != NULL) - { - garmin_ilink_t *ilink_ptr = xmalloc(sizeof(*ilink_ptr)); - - ilink_ptr->ref_count = 1; - ilink_ptr->lat = xlat; - ilink_ptr->lon = xlon; - ilink_ptr->next = NULL; - - if (anchor == NULL) { - gmsd->ilinks = ilink_ptr; - } else { - anchor->next = ilink_ptr; - } - anchor = ilink_ptr; + if (links == 0) { + /* Without links we need all informations from wpt */ + waypoint *tmp = gdb_reader_find_waypt(wpt, 0); + if (tmp != NULL) { + waypt_free(wpt); + wpt = waypt_dupe(tmp); + } + else { + if (waypt_bounds_valid(&bounds)) + warning(MYNAME ": (has bounds)\n"); + + warning(MYNAME ": Data corruption detected!\n"); + fatal(MYNAME ": Sleeping route point without coordinates!\n"); + } } - } - - gdb_fread(buff, 1); - gdb_is_valid(buff[0] == 0, prefix1, "\"Zero\" byte expected"); - gdb_fread_le(&maxlat, sizeof(maxlat), 32, prefix1, "max. latitude"); - gdb_fread_le(&maxlon, sizeof(maxlon), 32, prefix1, "max. longitude"); - - if (gdb_fread_flag(1)) /* link max alt validity + alt */ - gdb_fread(buff, 8); - - gdb_fread_le(&minlat, sizeof(minlat), 32, prefix1, "min. latitude"); - gdb_fread_le(&minlon, sizeof(minlon), 32, prefix1, "min. longitude"); - - if (gdb_fread_flag(1)) /* link min alt validity + alt */ - gdb_fread(buff, 2 * sizeof(int)); + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_2) { + FREAD(buf, 8); + if (gdb_ver >= GDB_VER_3) { + FREAD(buf, 2); + } + } +#if GDB_DEBUG + DBG(GDB_DBG_RTE, 1) + printf(MYNAME "-rte_pt \"%s\": coordinates = %c%0.6f, %c%0.6f\n", + nice(wpt->shortname), + wpt->latitude < 0 ? 'S' : 'N', wpt->latitude, + wpt->longitude < 0 ? 'W' : 'E', wpt->longitude); +#endif + wpt = gdb_add_route_waypt(rte, wpt, wpt_class); + if (wpt != NULL) { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + if (gmsd == NULL) { + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + } + GMSD_SET(wpt_class, wpt_class); + gmsd->ilinks = il_root; + il_root = NULL; + } - if (gdb_ver >= 2) - gdb_fread(buff, 8); /* unknown 8 bytes since gdb v2 */ - if (gdb_ver >= 3) - gdb_fread(buff, 2); /* unknown 8 bytes since gdb v3 */ - } - - /* This should normally never happen; end of route is handled in main loop before this */ + while (il_root) { + garmin_ilink_t *il = il_root; + il_root = il_root->next; + xfree(il); + } + } /* ENDFOR: for (i = 0; i < points; i++) */ - fatal(MYNAME "-%s: Unexpected end of route \"%s\"!", prefix1, xname); - return 0; + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + rte->rte_url = FREAD_CSTR; + } + else { + rte->rte_url = gdb_fread_strlist(); + + FREAD(buf, 4); /* ?????????????????????????????????? */ + FREAD(buf, 1); /* ?????????????????????????????????? */ + + rte->rte_desc = FREAD_CSTR; +#if 0 + /* replace CRLF's with ", " */ + if (rte->rte_desc) { + char *c = rte->rte_desc; + while ((c = strstr(c, "\r\n"))) { + *c++ = ','; + *c++ = ' '; + } + } +#endif + } + return rte; } +/*-----------------------------------------------------------------------------*/ static route_head * -gdb_read_track(const size_t max_file_pos) +read_track(void) { - char xname[GDB_NAME_BUFFERLEN]; - unsigned char xdisplay; - int xcolour; - int xlat; - int xlon; - int xtime = 0; - double xalt = unknown_alt; - double xdepth = unknown_alt; - double xtemp; - - char buff[128]; - int count; - - route_head *track; - waypoint *wpt; - - const char *prefix0 = "trk_read"; - const char *prefix = "trk_read_loop"; - - gdb_fread_str(xname, sizeof(xname)); + route_head *res; + int points, index; + char dummy; - gdb_fread_le(&xdisplay, sizeof(xdisplay), 8, prefix0, "display"); - gdb_fread_le(&xcolour, sizeof(xcolour), 32, prefix0, "colour"); - gdb_fread_le(&count, sizeof(count), 32, prefix0, "count"); + trk_ct++; - track = route_head_alloc(); - track->rte_name = xstrdup(xname); - track_add_head(track); + res = route_head_alloc(); + res->rte_name = FREAD_CSTR; +// res->rte_num = trk_ct; + + FREAD(&dummy, 1); /* display - 1 byte */ + FREAD_i32; /* color - 1 dword */ + + points = FREAD_i32; - while (count--) + for (index = 0; index < points; index++) { - gdb_fread_le(&xlat, sizeof(xlat), 32, prefix, "latitude"); - gdb_fread_le(&xlon, sizeof(xlon), 32, prefix, "longitude"); - - gdb_fread(buff, 1); /* altitude flag */ - if (buff[0] == 1) - gdb_fread_le(&xalt, sizeof(xalt), 64, prefix, "altitude"); - - gdb_fread(buff, 1); /* date/time flag */ - if (buff[0] == 1) - gdb_fread_le(&xtime, sizeof(xtime), 32, prefix, "time"); - - gdb_fread(buff, 1); /* depth flag */ - if (buff[0] == 1) - gdb_fread_le(&xdepth, sizeof(xdepth), 64, prefix, "depth"); - - gdb_fread(buff, 1); /* temperature flag */ - if (buff[0] == 1) - gdb_fread_le(&xtemp, sizeof(xtemp), 64, prefix, "temperature"); - - wpt = waypt_new(); - - wpt->latitude = GPS_Math_Semi_To_Deg(xlat); - wpt->longitude = GPS_Math_Semi_To_Deg(xlon); - wpt->creation_time = xtime; - wpt->microseconds = 0; - wpt->altitude = xalt; - wpt->depth = xdepth; - - gdb_is_validf(fabs(wpt->latitude) <= 90.0, prefix, "Invalid latitude (%f)", wpt->latitude); - - track_add_wpt(track, wpt); + waypoint *wpt = waypt_new(); + + trkpt_ct++; + + wpt->latitude = FREAD_LATLON; + wpt->longitude = FREAD_LATLON; + if (FREAD_C == 1) { + double alt = gbfgetdbl(fin); + if (alt < 1.0e24) wpt->altitude = alt; + } + if (FREAD_C == 1) { + wpt->creation_time = FREAD_i32; + } + if (FREAD_C == 1) { + wpt->depth = gbfgetdbl(fin); + } + if (FREAD_C == 1) { + wpt->temperature = gbfgetdbl(fin); + } + + track_add_wpt(res, wpt); } - if (gdb_ver >= 3) { - int url_ct; - - gdb_fread_le(&url_ct, sizeof(url_ct), 32, prefix, "number of urls (since v3)"); - while (url_ct > 0) { - url_ct--; - gdb_fread_str(xname, sizeof(xname)); - if ((track->rte_url == NULL) && (xname[0] != '\0')) - track->rte_url = xstrdup(xname); - } - } else { - gdb_fread_str(xname, sizeof(xname)); - if (xname[0] != '\0') - track->rte_url = xstrdup(xname); + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_3) { + res->rte_url = gdb_fread_strlist(); } - - return track; + else /* if (gdb_ver <= GDB_VER_2) */ { + res->rte_url = FREAD_CSTR; + } +#if GDB_DEBUG + DBG(GDB_DBG_TRK, res->rte_url) + printf(MYNAME "-trk \"%s\": url = %s\n", + res->rte_name, res->rte_url); +#endif + return res; } /*******************************************************************************/ static void -gdb_read_data(void) +init_reader(const char *fname) { - queue *elem, *temp; - int reclen, warnings; - char typ; - size_t curpos, anchor; - int wptclass; - - const char *prefix = "main_read_loop"; + fin = gbfopen_le(fname, "rb", MYNAME); + read_file_header(); + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_UTF8) + cet_convert_init(CET_CHARSET_UTF8, 1); + + QUEUE_INIT(&wayptq_in); + QUEUE_INIT(&wayptq_in_hidden); + + gdb_via = (gdb_opt_via && *gdb_opt_via) ? atoi(gdb_opt_via) : 0; + gdb_roadbook = (gdb_opt_roadbook && *gdb_opt_roadbook) ? atoi(gdb_opt_roadbook) : 0; + if (gdb_roadbook) /* higher priority */ gdb_via = 1; + + waypt_ct = 0; + waypth_ct = 0; + rtept_ct = 0; + trkpt_ct = 0; + rte_ct = 0; + trk_ct = 0; +} - QUEUE_INIT(&gdb_hidden); +static void +done_reader(void) +{ + disp_summary(fin); + gdb_flush_waypt_queue(&wayptq_in); + gdb_flush_waypt_queue(&wayptq_in_hidden); + gbfclose(fin); +} - warnings = 0; - - anchor = ftell(fin); +static void +read_data(void) +{ + int incomplete = 0; /* number of incomplete reads */ - /* we go twice through the file to keep sure, all waypoints - are loaded before any route has to be handled */ - - while (feof(fin) == 0) - { - - gdb_fread_le(&reclen, sizeof(reclen), 32, prefix, "record length"); - gdb_is_valid(reclen > 0 && reclen < 0x1F00000, prefix, "record length"); - gdb_fread(&typ, 1); - - curpos = ftell(fin); - - if (typ == 'W') - { - int delta; + for (;;) { + int len, delta; + char typ, dump; + gt_waypt_classes_e wpt_class; + gbsize_t pos; waypoint *wpt; + route_head *trk, *rte; - wpt = gdb_read_wpt(curpos + reclen, &wptclass); - if (wpt != NULL ) - { - if (wptclass == 0) { - waypt_add(wpt); - } - else if (gdb_via == 0) - ENQUEUE_TAIL(&gdb_hidden, &wpt->Q); - else - waypt_free(wpt); - } - delta = (int)((curpos + reclen) - ftell(fin)); - if (delta != 0) - { - if ((warnings & 1) == 0) - { - warnings |= 1; - warning(MYNAME "-%s: At least one incomplete waypoint (gdb v%d, %d byte(s) left).\n", prefix, gdb_ver, delta); - } - fseek(fin, curpos + reclen, SEEK_SET); - } - continue; - } - else if (typ == 'V') - break; + len = FREAD_i32; + FREAD(&typ, 1); + pos = gbftell(fin); - fseek(fin, curpos + reclen, SEEK_SET); - } - - clearerr(fin); - fseek(fin, anchor, SEEK_SET); - - - while (feof(fin) == 0) - { - gdb_fread_le(&reclen, sizeof(reclen), 32, prefix, "record length"); - gdb_is_valid(reclen > 0 && reclen < 0x1F00000, prefix, "record length"); - gdb_fread(&typ, 1); - - curpos = ftell(fin); - - if ((typ == 'R') || (typ == 'T')) - { - int flag, delta; + if (typ == 'V') break; /* break the loop */ - if (typ == 'R') - { - gdb_read_route(); - flag = 2; - } - else - { - gdb_read_track(curpos + reclen); - flag = 4; + dump = 1; + wpt_class = GDB_DEF_CLASS; + + switch(typ) { + case 'W': + wpt = read_waypoint(&wpt_class); + if ((gdb_via == 0) || (wpt_class == 0)) { + waypoint *dupe; + waypt_add(wpt); + dupe = waypt_dupe(wpt); + ENQUEUE_TAIL(&wayptq_in, &dupe->Q); + } + else + ENQUEUE_TAIL(&wayptq_in_hidden, &wpt->Q); + break; + case 'R': + rte = read_route(); + if (rte) route_add_head(rte); + break; + case 'T': + trk = read_track(); + if (trk) track_add_head(trk); + break; + default: + dump = 0; /* make a dump only for main types */ + break; } - delta = (int)((curpos + reclen) - ftell(fin)); - if (delta != 0) - { - if ((delta != reclen) && ((warnings & flag) == 0)) - { - warnings |= flag; - warning(MYNAME "-%s: At least one incomplete %s (gdb v%d, %d byte(s) left).\n", - prefix, (typ == 'R') ? "route" : "track", gdb_ver, delta); - } - fseek(fin, curpos + reclen, SEEK_SET); - } - } - else - { - if (typ == 'V') break; - switch(typ) - { - case 'D': break; - case 'L': break; - case 'W': break; - default: warning(MYNAME "-%s: Found unknown record type \"%c\" (gdb v%d)!\n", prefix, typ, gdb_ver); + delta = (pos + len) - gbftell(fin); + if (dump && delta) { + if (! incomplete++) { + warning(MYNAME ":==========================================\n"); + warning(MYNAME ":=== W A R N I N G ===\n"); + } + if (typ == 'W') + warning(MYNAME ":(%d%c-%02d): delta = %d (flag=%3d/%02x)-", + gdb_ver, typ, wpt_class, delta, waypt_flag, waypt_flag); + else + warning(MYNAME ":(%d%c): delta = %d -", gdb_ver, typ, delta); + if (delta > 0) { + int i; + char *buf = xmalloc(delta); + FREAD(buf, delta); + for (i = 0; i < delta; i++) { + warning(" %02x", (unsigned char)buf[i]); + } + xfree(buf); + } + warning("\n"); } - fseek(fin, curpos + reclen, SEEK_SET); - } + gbfseek(fin, pos + len, SEEK_SET); } - - QUEUE_FOR_EACH(&gdb_hidden, elem, temp) { /* finally kill our temporary queue */ - waypt_free((waypoint *) elem); - } -} - -/*******************************************************************************/ -/* %%% write support %%% */ -/*******************************************************************************/ - -/* helpers */ - -static waypoint ** -gdb_route_point_list(const route_head *route, int *count) -{ - waypoint **result; - queue *elem, *tmp; - int i = 0; - QUEUE_FOR_EACH((queue *)&route->waypoint_list, elem, tmp) - { - waypoint *wpt = (waypoint *)elem; - if ((gdb_via == 0) || - (gdb_detect_rtept_class(wpt) == GDB_DEFAULTWPTCLASS)) i++; - } - - *count = i; - if (i == 0) return NULL; - - result = xcalloc(i, sizeof(*result)); - - i = 0; - QUEUE_FOR_EACH((queue *)&route->waypoint_list, elem, tmp) - { - waypoint *wpt = (waypoint *)elem; - if ((gdb_via == 0) || - (gdb_detect_rtept_class(wpt) == GDB_DEFAULTWPTCLASS)) - result[i++] = wpt; - } - return result; -} - -static void -gdb_fwrite(const void *data, const size_t size) -{ - fwrite(data, size, 1, fout); -} - -static void -gdb_fwrite_str(const char *str, const int len) -{ - - if (len >= 0) - gdb_fwrite(str, len); /* write a string with fixed length */ - else - { - char *tmp = (str != NULL) ? (char *)str : ""; - gdb_fwrite(tmp, strlen(tmp) + 1); + if (incomplete) { + warning(MYNAME ":------------------------------------------\n"); + warning(MYNAME ": Please mail this information\n"); + warning(MYNAME " and, if you can, the used GDB file\n"); + warning(MYNAME ": to gpsbabel-misc@lists.sourceforge.net\n"); + warning(MYNAME ":==========================================\n"); } } -static void -gdb_fwrite_le(const void *data, const size_t size) -{ - int i; - short s; - char buff[8]; - - switch(size) - { - case 1: - gdb_fwrite(data, 1); - break; - - case 2: /* sizeof(short): */ - s = *(short *)data; - le_write16(&s, s); - gdb_fwrite(&s, 2); - break; - - case 4: /* sizeof(int): */ - i = *(int *)data; - le_write32(&i, i); - gdb_fwrite(&i, 4); - break; - - case 8: /* sizeof(double): */ - le_read64(buff, data); - gdb_fwrite(buff, 8); - break; - - default: - fatal(MYNAME "-write_le: Unsupported data size (%lu)!\n", - (unsigned long) size); - } -} +/*******************************************************************************/ static void -gdb_fwrite_alt(const double alt, const double unknown_value) +reset_short_handle(const char *defname) { - char c0 = 0; - char c1 = 1; - - if (alt != unknown_value) /* proximity / depth / altitude */ - { - gdb_fwrite(&c1, 1); - gdb_fwrite_le(&alt, sizeof(alt)); - } - else - gdb_fwrite(&c0, 1); /* no value */ -} - -static void -gdb_fwrite_int(const int data) -{ - gdb_fwrite_le(&data, sizeof(data)); -} - -static void -gdb_fwrite_icon(const waypoint *wpt) /* partly taken from mapsource.c */ -{ - int icon; - char buff[128]; - - if ( /* handle custom icons, which are linked to -2 in garmin_tables.c */ - (wpt->icon_descr != NULL) && - (sscanf(wpt->icon_descr, "%s%d", buff, &icon) == 2) && - (case_ignore_strcmp(buff, "Custom") == 0) && - (icon >= 0) && (icon <= 63) - ) - { - icon += 500; - } - else - { - /* might need to change this to handle version dependent icon handling */ - icon = gt_find_icon_number_from_desc(wpt->icon_descr, GDB); - if (get_cache_icon(wpt) /* && wpt->icon_descr && (strcmp(wpt->icon_descr, "Geocache Found") != 0)*/) - { - icon = gt_find_icon_number_from_desc(get_cache_icon(wpt), MAPSOURCE); - } - } - gdb_fwrite_le(&icon, sizeof(icon)); + if (short_h != NULL) + mkshort_del_handle(&short_h); + + short_h = mkshort_new_handle(); + + setshort_length(short_h, GDB_NAME_BUFFERLEN); + setshort_badchars(short_h, ""); + setshort_mustupper(short_h, 0); + setshort_mustuniq(short_h, 1); + setshort_whitespace_ok(short_h, 1); + setshort_repeating_whitespace_ok(short_h, 0); + setshort_defname(short_h, defname); } -/*******************************************************************************/ -/* %%% write file header %%% */ -/*-----------------------------------------------------------------------------*/ - +/* ----------------------------------------------------------------------------*/ static void -gdb_write_file_header(void) +write_header(void) { char buff[128], tbuff[32]; char *c; int len; struct tm tm; - gdb_fwrite_str("MsRcf", -1); - gdb_fwrite_int(2); + FWRITE_CSTR("MsRcf"); + FWRITE_i32(2); strncpy(buff, "Dx", sizeof(buff)); buff[1] = 'k' - 1 + gdb_ver; - gdb_fwrite_str(buff, -1); + FWRITE_CSTR(buff); #if 0 /* Take this if anything is wrong with our self generated watermark */ - strncpy(buff, "A].SQA*Dec 27 2004*17:40:51", sizeof(buff)); /* MapSource V6.5 */ + strncpy(buff, "A].SQA*Dec 27 2004*17:40:51", sizeof(buff)); /* MapSource V6.5 */ #else /* This is our "Watermark" to show this file was created by GPSbabel */ /* history: - strncpy(buff, "A].GPSBabel_1.2.7-beta*Sep 13 2005*20:10:00", sizeof(buff)); // gpsbabel V1.2.7 BETA - strncpy(buff, "A].GPSBabel_1.2.8-beta*Jan 18 2006*20:11:00", sizeof(buff)); // gpsbabel 1.2.8-beta01182006_clyde - strncpy(buff, "A].GPSBabel_1.2.8-beta*Apr 18 2006*20:12:00", sizeof(buff)); // gpsbabel 1.2.8-beta20060405 - strncpy(buff, "A].GPSBabel-1.3*Jul 02 2006*20:13:00", sizeof(buff)); // gpsbabel 1.3.0 - strncpy(buff, "A].GPSBabel-1.3.1*Sep 03 2006*20:14:00", sizeof(buff)); // gpsbabel 1.3.1 - */ - - /* - New since 11/01/2006: - version: version and release of gpsbabel (defined in configure.in) - timestamp: date and time of gdb.c (handled by CVS) + + "A].GPSBabel_1.2.7-beta*Sep 13 2005*20:10:00" - gpsbabel V1.2.7 BETA + "A].GPSBabel_1.2.8-beta*Jan 18 2006*20:11:00" - gpsbabel 1.2.8-beta01182006_clyde + "A].GPSBabel_1.2.8-beta*Apr 18 2006*20:12:00" - gpsbabel 1.2.8-beta20060405 + "A].GPSBabel-1.3*Jul 02 2006*20:13:00" - gpsbabel 1.3.0 + "A].GPSBabel-1.3.1*Sep 03 2006*20:14:00" - gpsbabel 1.3.1 + + New since 11/01/2006: + + version: version and release of gpsbabel (defined in configure.in) + timestamp: date and time of gdb.c (handled by CVS) + + "A].GPSBabel-1.3.2*Nov 01 2006*22:23:39" - gpsbabel 1.3.2 + "A].GPSBabel-beta20061125*Feb 06 2007*23:24:14" - gpsbabel beta20061125 + */ + memset(&tm, 0, sizeof(tm)); sscanf(gdb_release_date+7, "%d/%d/%d %d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); tm.tm_year -= 1900; @@ -1238,591 +1066,525 @@ gdb_write_file_header(void) c = buff; while ((c = strchr(c, '*'))) *c++ = '\0'; - gdb_fwrite_int(len); - gdb_fwrite_str(buff, len + 1); - - gdb_fwrite_str("MapSource", -1); /* MapSource magic */ + FWRITE_i32(len); + FWRITE(buff, len + 1); + FWRITE_CSTR("MapSource"); /* MapSource magic */ } -static void -gdb_reset_short_handle(void) -{ - if (gdb_short_handle != NULL) - mkshort_del_handle(&gdb_short_handle); - - gdb_short_handle = mkshort_new_handle(); - - setshort_length(gdb_short_handle, GDB_NAME_BUFFERLEN); - setshort_badchars(gdb_short_handle, ""); - setshort_mustupper(gdb_short_handle, 0); - setshort_mustuniq(gdb_short_handle, 1); - setshort_whitespace_ok(gdb_short_handle, 1); - setshort_repeating_whitespace_ok(gdb_short_handle, 1); -} - -/*******************************************************************************/ -/* %%% write waypoints %%% */ /*-----------------------------------------------------------------------------*/ -static void -gdb_write_waypt(const waypoint *wpt, const int hidden) +static void +write_waypoint( + const waypoint *wpt, const char *shortname, garmin_fs_t *gmsd, + const int icon, const int display) { - int i; - char ffbuf[32], zbuf[32]; - char c0 = 0; - char c1 = 1; - garmin_fs_t *gmsd; - unsigned char wpt_class; - char *ident; + char zbuf[32], ffbuf[32]; + int wpt_class; - gmsd = GMSD_FIND(wpt); + waypt_ct++; /* increase informational number of written waypoints */ - gdb_is_validf((fabs(wpt->latitude) <= 90), "wpt_write", - "%s: Invalid latitude (%f) detected\n", wpt->shortname, wpt->latitude); - + memset(zbuf, 0, sizeof(zbuf)); memset(ffbuf, 0xFF, sizeof(ffbuf)); - memset(zbuf, 0x00, sizeof(zbuf)); - - ident = wpt->shortname; /* paranoia */ - if (global_opts.synthesize_shortnames || (ident == NULL) || (*ident == '\0')) - { - ident = mkshort_from_wpt(gdb_short_handle, wpt); - } - gdb_fwrite_str(ident, -1); - wpt_class = GMSD_GET(wpt_class, (hidden != 0) ? GDB_HIDDENROUTEWPTCLASS : GDB_DEFAULTWPTCLASS); - gdb_fwrite_int(wpt_class); /* class */ - gdb_fwrite_str(GMSD_GET(cc, ""), -1); /* country code */ + wpt_class = wpt->microseconds; /* trick */ - gdb_fwrite(zbuf, 4); /* subclass part 1 */ - gdb_fwrite(ffbuf, 12); /* subclass part 2 */ - gdb_fwrite(zbuf, 2); /* subclass part 3 */ - gdb_fwrite(ffbuf, 4); /* unknown */ - - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->latitude)); - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->longitude)); - - gdb_fwrite_alt(wpt->altitude, unknown_alt); /* altitude */ + FWRITE_CSTR(shortname); /* uniqe (!!!) shortname */ + FWRITE_i32(wpt_class); /* waypoint class */ + FWRITE_CSTR(GMSD_GET(cc, "")); /* country code */ - gdb_fwrite_str((wpt->notes != NULL) ? wpt->notes : wpt->description, -1); /* notes/comment/descr */ - - gdb_fwrite_alt(GMSD_GET(proximity, 0), 0); /* proximity */ + if (wpt_class != 0) waypth_ct++; - switch(GMSD_GET(display, 0)) { /* display */ - case gt_display_mode_symbol: i = gt_gdb_display_mode_symbol; break; - case gt_display_mode_symbol_and_comment: i = gt_gdb_display_mode_symbol_and_comment; break; - default: i = gt_gdb_display_mode_symbol_and_name; break; +#ifdef GMSD_EXPERIMENTAL + if (gmsd && gmsd->flags.subclass && (wpt_class >= gt_waypt_class_map_point)) { + FWRITE(gmsd->subclass, sizeof(gmsd->subclass)); } - gdb_fwrite_int(i); - - gdb_fwrite_int(0); /* colour */ - - gdb_fwrite_icon(wpt); /* icon */ - gdb_fwrite_str(GMSD_GET(city, ""), -1); /* city */ - gdb_fwrite_str(GMSD_GET(state, ""), -1); /* state */ - gdb_fwrite_str(GMSD_GET(facility, ""), -1); /* facility */ - - gdb_fwrite(zbuf, 1); /* unknown */ - - gdb_fwrite_alt(GMSD_GET(depth, 0), 0); /* depth */ - - gdb_fwrite(zbuf, 3); /* three unknown bytes */ - gdb_fwrite(zbuf, 4); /* four unknown bytes */ - - if (hidden == 0) - gdb_fwrite_str(wpt->url, -1); /* URL */ else - gdb_fwrite_str(wpt->description, -1); /* description for hidden waypoints */ - - i = GMSD_GET(category, gdb_category); /* category */ - gdb_fwrite_le(&i, 2); - - gdb_fwrite_alt(GMSD_GET(temperature, 0), 0); /* temperature */ - - if (wpt->creation_time > 0) /* creation time */ +#endif { - gdb_fwrite(&c1, 1); - gdb_fwrite_int(wpt->creation_time); + FWRITE(zbuf, 4); /* subclass part 1 */ + FWRITE(ffbuf, 12); /* subclass part 2 */ + FWRITE(zbuf, 2); /* subclass part 3 */ + FWRITE(ffbuf, 4); /* unknown */ } - else - gdb_fwrite(&c0, 1); - -} -static void -gdb_write_waypt_cb(const waypoint *wpt) /* called by waypt_disp over all waypoints */ -{ - int reclen; - size_t pos; - waypoint *tmp; - - /* check for duplicate waypoints */ - if (NULL != gdb_find_wpt_q_by_name(&gdb_hidden, wpt->shortname)) - return; + FWRITE_LATLON(wpt->latitude); /* latitude */ + FWRITE_LATLON(wpt->longitude); /* longitude */ + FWRITE_DBL(wpt->altitude, unknown_alt); /* altitude */ + FWRITE_CSTR(wpt->notes); + FWRITE_DBL(GMSD_GET(proximity, 0), 0); /* proximity */ + FWRITE_i32(display); /* display */ + FWRITE_i32(0); /* color (colour) */ + FWRITE_i32(icon); /* icon */ + FWRITE_CSTR(GMSD_GET(city, "")); /* city */ + FWRITE_CSTR(GMSD_GET(state, "")); /* state */ + FWRITE_CSTR(GMSD_GET(facility, "")); /* facility */ + FWRITE_C(0); /* unknown */ + FWRITE_DBL(GMSD_GET(depth, 0), 0); /* depth */ + + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + char *descr; + + FWRITE(zbuf, 3); + FWRITE(zbuf, 4); + descr = (wpt_class < gt_waypt_class_map_point) ? + wpt->url : wpt->description; + if ((descr != NULL) && (wpt_class >= gt_waypt_class_map_point) && \ + (strcmp(descr, wpt->shortname) == 0)) + descr = NULL; + FWRITE_CSTR(descr); + } + else /* if (gdb_ver > GDB_VER_3) */ { + int cnt; + url_link *url_next; - gdb_fwrite_int(0); - gdb_fwrite_str("W", 1); - - pos = ftell(fout); - gdb_write_waypt(wpt, 0); - reclen = ftell(fout) - pos; - - fseek(fout, pos - 5, SEEK_SET); - gdb_fwrite_int(reclen); - - fseek(fout, pos + reclen, SEEK_SET); + FWRITE(zbuf, 6); + FWRITE_CSTR(wpt->description); + + cnt = 0; + if (wpt->url) cnt++; + for (url_next = wpt->url_next; (url_next); url_next = url_next->url_next) + if (url_next->url) cnt++; + FWRITE_i32(cnt); + if (wpt->url) FWRITE_CSTR(wpt->url); + for (url_next = wpt->url_next; (url_next); url_next = url_next->url_next) + if (url_next->url) FWRITE_CSTR(url_next->url); + } + + FWRITE_i16(GMSD_GET(category, gdb_category)); + FWRITE_DBL(GMSD_GET(temperature, 0), 0); + FWRITE_TIME(wpt->creation_time); - tmp = waypt_dupe(wpt); - ENQUEUE_TAIL(&gdb_hidden, &tmp->Q); /* add this point to our internal queue */ + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_3) { + FWRITE(zbuf, 6); + } } static void -gdb_write_rtewpt_cb(const waypoint *wpt) /* called by waypt_disp (route points) */ +route_compute_bounds(const route_head *rte, bounds *bounds) { - int reclen; - size_t pos; - waypoint *tmp, *dupe; - - tmp = gdb_find_wpt_q_by_name(&gdb_hidden, wpt->shortname); - if (tmp == NULL) - { - tmp = find_waypt_by_name(wpt->shortname); - - gdb_fwrite_int(0); - gdb_fwrite_str("W", 1); - - pos = ftell(fout); - gdb_write_waypt(wpt, (tmp == NULL)); - reclen = ftell(fout) - pos; - - fseek(fout, pos - 5, SEEK_SET); - gdb_fwrite_int(reclen); - - fseek(fout, pos + reclen, SEEK_SET); - - dupe = waypt_dupe(wpt); - ENQUEUE_TAIL(&gdb_hidden, &dupe->Q); /* add this point to our internal queue */ + queue *elem, *tmp; + waypt_init_bounds(bounds); + QUEUE_FOR_EACH((queue *)&rte->waypoint_list, elem, tmp) { + waypoint *wpt = (waypoint *)elem; + waypt_add_to_bounds(bounds, wpt); } } -/*******************************************************************************/ -/* %%% write routes %%% */ -/*-----------------------------------------------------------------------------*/ - static void -gdb_write_route(const route_head *route, const waypoint **list, const int count) +route_write_bounds(bounds *bounds) { - int i, wpt_class; - char buff[128], zbuff[32], ffbuff[32]; - waypoint *prev = NULL; - const char c0 = 0; - const char c1 = 1; - const char c3 = 3; - double maxlat = -90; - double minlat = +90; - double maxlon = -180; - double minlon = +180; - double maxalt = -unknown_alt; - double minalt = +unknown_alt; - - memset(zbuff, 0, sizeof(zbuff)); - memset(ffbuff, 0xFF, sizeof(ffbuff)); - - for (i = 0; i < count; i++) - { - const waypoint *wpt = list[i]; - - if (wpt->latitude > maxlat) maxlat = wpt->latitude; - if (wpt->latitude < minlat) minlat = wpt->latitude; - if (wpt->longitude > maxlon) maxlon = wpt->longitude; - if (wpt->longitude < minlon) minlon = wpt->longitude; - if (wpt->altitude != unknown_alt) - { - if (wpt->altitude > maxalt) maxalt = wpt->altitude; - if (wpt->altitude < minalt) minalt = wpt->altitude; - } - } - - { - char *cname; - - if (route->rte_name == NULL) - { - snprintf(buff, sizeof(buff), "Route%04d", route->rte_num); - cname = mkshort(gdb_short_handle, buff); - } - else - cname = mkshort(gdb_short_handle, route->rte_name); - - gdb_fwrite_str(cname, -1); - xfree(cname); + if (waypt_bounds_valid(bounds)) { + FWRITE_C(0); + FWRITE_LATLON(bounds->max_lat); + FWRITE_LATLON(bounds->max_lon); + FWRITE_DBL(bounds->max_alt, -(unknown_alt)); + FWRITE_LATLON(bounds->min_lat); + FWRITE_LATLON(bounds->min_lon); + FWRITE_DBL(bounds->min_alt, unknown_alt); } + else FWRITE_C(1); +} - gdb_fwrite(&c0, 1); /* auto_name */ +static void +write_route(const route_head *rte, const char *rte_name) +{ + bounds bounds; + int points, index; + queue *elem, *tmp; + char zbuf[32], ffbuf[32]; - if (count == 1) gdb_fwrite(&c1, 1); /* skip max data */ - else - { - gdb_fwrite(&c0, 1); /* ??? */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(maxlat)); /* maximum latitude over route */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(maxlon)); /* maximum longitude over route */ - gdb_fwrite_alt(maxalt, unknown_alt); /* maximum altitude over route */ - - gdb_fwrite_int(GPS_Math_Deg_To_Semi(minlat)); /* minimum latitude over route */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(minlon)); /* minimum longitude over route */ - gdb_fwrite_alt(minalt, -unknown_alt); /* minimum altitude over route */ - } + memset(zbuf, 0, sizeof(zbuf)); + memset(ffbuf, 0xFF, sizeof(ffbuf)); - gdb_fwrite_int(count); /* number of points in route */ - - for (i = 0; i < count; i++) - { - const waypoint *wpt = list[i]; - garmin_fs_t *gmsd; - - gmsd = GMSD_FIND(wpt); - if (gmsd && gmsd->flags.wpt_class) - wpt_class = gmsd->wpt_class; - else - wpt_class = gdb_detect_rtept_class(wpt); - - if (prev != NULL) - { - gdb_fwrite_int(2); /* route link details */ + FWRITE_CSTR(rte_name); + FWRITE_C(0); /* display/autoname - 1 byte */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(prev->latitude)); /* ilink step 1 (end point 1) */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(prev->longitude)); - gdb_fwrite_alt(prev->altitude, unknown_alt); + route_compute_bounds(rte, &bounds); + route_write_bounds(&bounds); - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->latitude)); /* ilink step 2 (end point 2) */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->longitude)); - gdb_fwrite_alt(wpt->altitude, unknown_alt); + points = ELEMENTS(rte); + FWRITE_i32(points); + + index = 0; + + QUEUE_FOR_EACH((queue *)&rte->waypoint_list, elem, tmp) { + + waypoint *wpt = (waypoint *)elem; + waypoint *test; + garmin_fs_t *gmsd = NULL; + int wpt_class; - if (wpt->latitude > prev->latitude) /* get maximum lat, lon and alt */ - { - maxlat = wpt->latitude; - minlat = prev->latitude; - } - else - { - maxlat = prev->latitude; - minlat = wpt->latitude; - } - if (wpt->longitude > prev->longitude) - { - maxlon = wpt->longitude; - minlon = prev->longitude; + index++; + rtept_ct++; /* increase informational number of written route points */ + + test = gdb_find_wayptq(&wayptq_out, wpt, 1); + if (test != NULL) wpt = test; + else { + fatal(MYNAME ": Sorry, that should never happen!!!\n"); } + + gmsd = GMSD_FIND(wpt); + + /* extra_data may contain a modified shortname */ + FWRITE_CSTR((wpt->extra_data) ? (char *)wpt->extra_data : wpt->shortname); + + wpt_class = wpt->microseconds; /* trick */ + + FWRITE_i32(wpt_class); /* waypoint class */ + FWRITE_CSTR(GMSD_GET(cc, "")); /* country */ +#ifdef GMSD_EXPERIMENTAL + if (gmsd && gmsd->flags.subclass && (wpt_class >= gt_waypt_class_map_point)) + FWRITE(gmsd->subclass, sizeof(gmsd->subclass)); else +#endif { - maxlon = prev->longitude; - minlon = wpt->longitude; + FWRITE(zbuf, 4); /* subclass part 1 */ + FWRITE(ffbuf, 12); /* subclass part 2 */ + FWRITE(zbuf, 2); /* subclass part 3 */ + FWRITE(ffbuf, 4); /* unknown */ } - if (wpt->altitude != unknown_alt) - { - maxalt = wpt->altitude; - minalt = wpt->altitude; - } - else - { - maxalt = -unknown_alt; - minalt = +unknown_alt; + + FWRITE_C(0); /* unknown value or string */ + FWRITE_C(3); /* unknown 18 bytes starting with 0x03 */ + FWRITE(zbuf, 3); + FWRITE(ffbuf, 4); + FWRITE(zbuf, 10); + + if (index == points) { + FWRITE_i32(0); /* no more steps */ + FWRITE_C(1); /* skip bounds */ } - if (prev->altitude != unknown_alt) - { - if (prev->altitude > maxalt) maxalt = prev->altitude; - if (prev->altitude < minalt) minalt = prev->altitude; + else /* if (index < points) */ { + waypoint *next = (waypoint *)tmp; + + FWRITE_i32(2); /* two interstep links */ + + FWRITE_LATLON(wpt->latitude); + FWRITE_LATLON(wpt->longitude); + FWRITE_DBL(wpt->altitude, unknown_alt); + FWRITE_LATLON(next->latitude); + FWRITE_LATLON(next->longitude); + FWRITE_DBL(next->altitude, unknown_alt); + + waypt_init_bounds(&bounds); + waypt_add_to_bounds(&bounds, wpt); + waypt_add_to_bounds(&bounds, next); + route_write_bounds(&bounds); + } - gdb_fwrite(&c0, 1); /* ??? */ - - gdb_fwrite_int(GPS_Math_Deg_To_Semi(maxlat)); /* maximum coords & altitude */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(maxlon)); - gdb_fwrite_alt(maxalt, unknown_alt); - - gdb_fwrite_int(GPS_Math_Deg_To_Semi(minlat)); /* minimum coords & altitude */ - gdb_fwrite_int(GPS_Math_Deg_To_Semi(minlon)); - gdb_fwrite_alt(minalt, -unknown_alt); - - if (gdb_ver >= 2) - gdb_fwrite(ffbuff, 8); - } - - gdb_fwrite_str(wpt->shortname, -1); /* short name */ - - gdb_fwrite_int(wpt_class); /* class */ - gdb_fwrite_str(GMSD_GET(cc, ""), -1); /* country */ - - gdb_fwrite(zbuff, 4); /* subclass part 1 */ - gdb_fwrite(ffbuff, 12); /* subclass part 2 */ - gdb_fwrite(zbuff, 2); /* subclass part 3 */ - gdb_fwrite(ffbuff, 4); /* unknown */ - - gdb_fwrite(&c0, 1); /* unknown value or string */ - gdb_fwrite(&c3, 1); /* unknown 18 bytes starting with 0x03 */ - gdb_fwrite(zbuff, 3); - gdb_fwrite(ffbuff, 4); - gdb_fwrite(zbuff, 10); - - prev = (waypoint *)wpt; + /* VERSION DEPENDENT CODE */ + if (gdb_ver >= GDB_VER_2) { + FWRITE(ffbuf, 8); + if (gdb_ver >= GDB_VER_3) + FWRITE(zbuf, 2); + } } - - gdb_fwrite_int(0); /* Zero interlink steps */ - gdb_fwrite(&c1, 1); - if (gdb_ver >= 2) - gdb_fwrite(ffbuff, 8); - - gdb_fwrite_str(route->rte_url, -1); + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + FWRITE_CSTR(rte->rte_url); + } + else /* if (gdb_ver >= GDB_VER_3) */ { + FWRITE_CSTR_LIST(rte->rte_url); + FWRITE_i32(0x0E); /* color ??? */ + FWRITE_C(0); + FWRITE_CSTR(rte->rte_desc); + } } static void -gdb_write_route_cb(const route_head *route) +write_track(const route_head *trk, const char *trk_name) { - int reclen; - size_t pos; - int count; - waypoint **list; + queue *elem, *tmp; + int points = ELEMENTS(trk); - list = gdb_route_point_list(route, &count); - if (count == 0) return; /* don't write empty routes */ + FWRITE_CSTR(trk_name); + FWRITE_C(0); + FWRITE_i32(0); - gdb_fwrite_int(0); - gdb_fwrite_str("R", 1); - - pos = ftell(fout); - gdb_write_route(route, (const waypoint**)list, count); - reclen = ftell(fout) - pos; - - fseek(fout, pos - 5, SEEK_SET); - gdb_fwrite_int(reclen); + FWRITE_i32(points); /* total number of waypoints in waypoint list */ - fseek(fout, pos + reclen, SEEK_SET); + QUEUE_FOR_EACH((queue *)&trk->waypoint_list, elem, tmp) + { + waypoint *wpt = (waypoint *)elem; + + trkpt_ct++; /* increase informational number of written route points */ + + FWRITE_LATLON(wpt->latitude); + FWRITE_LATLON(wpt->longitude); + FWRITE_DBL(wpt->altitude, unknown_alt); + FWRITE_TIME(wpt->creation_time); + FWRITE_DBL(wpt->depth, unknown_alt); + FWRITE_DBL(wpt->temperature, 0); + } + + /* finalize track */ - xfree(list); + /* VERSION DEPENDENT CODE */ + if (gdb_ver <= GDB_VER_2) { + FWRITE_CSTR(trk->rte_url); + } + else /* if (gdb_ver >= GDB_VER_3 */ { + FWRITE_CSTR_LIST(trk->rte_url); + } } -/*******************************************************************************/ -/* %%% write tracks %%% */ /*-----------------------------------------------------------------------------*/ -static void -gdb_write_track(const route_head *track) +static void +finalize_item(const gbsize_t anchor) { - char buff[128]; - const char c0 = 0; - const char c1 = 1; - queue *elem, *tmp; - int count = track->rte_waypt_ct; - - { - char *cname; - - if (track->rte_name == NULL) - { - snprintf(buff, sizeof(buff), "Track%04d", track->rte_num); - cname = mkshort(gdb_short_handle, buff); - } - else - cname = mkshort(gdb_short_handle, track->rte_name); - - gdb_fwrite_str(cname, -1); - xfree(cname); - } - - gdb_fwrite(&c0, 1); /* display */ - gdb_fwrite_int(0); /* xcolour */ - gdb_fwrite_int(count); + gbsize_t mark; + int len; - QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) - { - waypoint *wpt = (waypoint *)elem; - - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->latitude)); - gdb_fwrite_int(GPS_Math_Deg_To_Semi(wpt->longitude)); - gdb_fwrite_alt(wpt->altitude, unknown_alt); /* altitude */ - + mark = gbftell(fout); + len = mark - anchor; + gbfseek(fout, -(len + 5), SEEK_CUR); + FWRITE_i32(mark - anchor); + gbfseek(fout, len + 1, SEEK_CUR); +} + +/*-----------------------------------------------------------------------------*/ - if (wpt->creation_time > 0) /* creation time */ - { - gdb_fwrite(&c1, 1); - gdb_fwrite_int(wpt->creation_time); - } - else - gdb_fwrite(&c0, 1); - - gdb_fwrite_alt(wpt->depth, unknown_alt); /* depth */ - gdb_fwrite(&c0, 1); /* temperature */ +static char +str_not_equal(const char *s1, const char *s2) +{ + if (s1) { + if (!s2) return 1; + if (strcmp(s1, s2) != 0) return 1; + else return 0; } - gdb_fwrite_str(track->rte_url, -1); + else if (s2) return 1; + else return 0; } static void -gdb_write_track_cb(const route_head *track) /* called from track_disp_all */ +write_waypoint_cb(const waypoint *refpt) { - int reclen; - size_t pos; - - if (track->rte_waypt_ct <= 0) return; /* don't write empty tracks */ - - gdb_fwrite_int(0); - gdb_fwrite_str("T", 1); - - pos = ftell(fout); - - gdb_write_track(track); + garmin_fs_t *gmsd; + waypoint *test; + gbsize_t anchor; - reclen = ftell(fout) - pos; - fseek(fout, pos - 5, SEEK_SET); - gdb_fwrite_int(reclen); + /* do this when backup always happens in main */ - fseek(fout, pos + reclen, SEEK_SET); -} + rtrim(((waypoint *)refpt)->shortname); + test = gdb_find_wayptq(&wayptq_out, refpt, 1); -/*******************************************************************************/ + if ((test != NULL) && (route_flag == 0)) { + if ((str_not_equal(test->description, refpt->description)) || + (str_not_equal(test->notes, refpt->notes)) || + (str_not_equal(test->url, refpt->url))) + test = NULL; + } -static void -gdb_write_data(void) -{ - queue *temp, *elem; - char c1 = 1; + if (test == NULL) { + int icon, display, wpt_class; + char *name; + waypoint *wpt = waypt_dupe(refpt); + + ENQUEUE_TAIL(&wayptq_out, &wpt->Q); + + FWRITE_i32(-1); + FWRITE_C('W'); + anchor = gbftell(fout); + + /* prepare the waypoint */ + gmsd = GMSD_FIND(wpt); - QUEUE_INIT(&gdb_hidden); /* contains all written waypts & rtepts */ + wpt_class = GMSD_GET(wpt_class, -1); + if (wpt_class == -1) + wpt_class = (route_flag) ? GDB_DEF_HIDDEN_CLASS : GDB_DEF_CLASS; + wpt->microseconds = wpt_class; /* trick, we need this for the route(s) */ + + icon = GMSD_GET(icon, -1); + if (icon < 0) { + if (wpt->icon_descr) + icon = gt_find_icon_number_from_desc(wpt->icon_descr, GDB); + else + icon = GDB_DEF_ICON; + } - /* (doing_wpts) */ - - gdb_reset_short_handle(); - waypt_disp_all(gdb_write_waypt_cb); - - /* (doing_rtes) */ - - gdb_reset_short_handle(); - setshort_defname(gdb_short_handle, "Route"); - if (gdb_via == 0) - { - /* find out all route points we have to write as a "HIDDEN CLASS" waypoint */ - route_disp_all(NULL, NULL, gdb_write_rtewpt_cb); - } - route_disp_all(gdb_write_route_cb, NULL, NULL); - QUEUE_FOR_EACH(&gdb_hidden, elem, temp) { /* vaporize our temporary queue */ - waypt_free((waypoint *) elem); - } + switch(GMSD_GET(display, -1)) { /* display */ + case -1: + if (wpt_class < 8) + display = gt_gdb_display_mode_symbol_and_name; + else + display = gt_gdb_display_mode_symbol; + break; + case gt_display_mode_symbol: + display = gt_gdb_display_mode_symbol; + break; + case gt_display_mode_symbol_and_comment: + display = gt_gdb_display_mode_symbol_and_comment; + break; + default: + display = gt_gdb_display_mode_symbol_and_name; + break; + } - /* (doing_trks) */ - - gdb_reset_short_handle(); - setshort_defname(gdb_short_handle, "Track"); - track_disp_all(gdb_write_track_cb, NULL, NULL); + name = wpt->shortname; + + if (global_opts.synthesize_shortnames || (*name == '\0')) { + name = wpt->notes; + if (!name) name = wpt->description; + if (!name) name = wpt->shortname; + } + + name = mkshort(short_h, name); + wpt->extra_data = (void *)name; + write_waypoint(wpt, name, gmsd, icon, display); - gdb_fwrite_int(2); /* finalize gdb with empty map segment */ - gdb_fwrite_str("V", -1); - gdb_fwrite(&c1, 1); + finalize_item(anchor); + } } -/*******************************************************************************/ - static void -gdb_init_opts(const char op) /* 1 = read; 2 = write */ +write_route_cb(const route_head *rte) { - gdb_via = 0; - gdb_category = 0; - gdb_ver = 2; + gbsize_t anchor; + char *name; + char buf[32]; - if (gdb_opt_via != NULL) /* opt_via present in both ops */ - { - if ((case_ignore_strcmp(gdb_opt_via, GDB_OPT_VIA) == 0) || - (*gdb_opt_via == '\0')) - gdb_via = 1; - else - gdb_via = atoi(gdb_opt_via); - } + if (ELEMENTS(rte) <= 0) return; - if (op & 2) /* writer opts */ - { - if ((gdb_opt_category != NULL) && - (case_ignore_strcmp(gdb_opt_category, GDB_OPT_CATEGORY) != 0) && - (*gdb_opt_category != '\0')) - { - gdb_category = atoi(gdb_opt_category); - if ((gdb_category < 1) || (gdb_category > 16)) - fatal(MYNAME ": Unsupported category \"%s\"!\n", gdb_opt_category); - gdb_category = 1 << (gdb_category - 1); - } - - gdb_ver = atoi(gdb_opt_ver); - if ((gdb_ver < GDB_VER_MIN) || (gdb_ver > GDB_VER_MAX)) - fatal(MYNAME ": Unsupported version \"%s\"!\n", gdb_opt_ver); + if (rte->rte_name == NULL) { + snprintf(buf, sizeof(buf), "Route%04d", rte->rte_num); + name = mkshort(short_h, buf); } -} + else + name = mkshort(short_h, rte->rte_name); + + rte_ct++; /* increase informational number of written routes */ -/*******************************************************************************/ -/* %%% global cb's %%% */ -/*******************************************************************************/ + FWRITE_i32(-1); + FWRITE_C('R'); -static void -gdb_rd_init(const char *fname) -{ - gdb_init_opts(1); - - fin_name = xstrdup(fname); - fin = xfopen(fname, "rb", MYNAME); - gdb_read_file_header(); - - if (gdb_ver >= 3) cet_convert_init(CET_CHARSET_UTF8, 1); + anchor = gbftell(fout); + write_route(rte, name); + finalize_item(anchor); + + xfree(name); } static void -gdb_wr_init(const char *fname) +write_track_cb(const route_head *trk) { - gdb_init_opts(2); + gbsize_t anchor; + char *name; + char buf[32]; - fout_name = xstrdup(fname); - fout = xfopen(fname, "wb", MYNAME); - gdb_short_handle = NULL; - QUEUE_INIT(&gdb_hidden); -} + if (ELEMENTS(trk) <= 0) return; + + if (trk->rte_name == NULL) { + snprintf(buf, sizeof(buf), "Track%04d", trk->rte_num); + name = mkshort(short_h, buf); + } + else + name = mkshort(short_h, trk->rte_name); -static void -gdb_rd_deinit(void) -{ - fclose(fin); - xfree(fin_name); - fin_name = NULL; + trk_ct++; /* increase informational number of written tracks */ + + FWRITE_i32(-1); + FWRITE_C('T'); + + anchor = gbftell(fout); + write_track(trk, name); + finalize_item(anchor); + + xfree(name); } +/*-----------------------------------------------------------------------------*/ + static void -gdb_wr_deinit(void) +init_writer(const char *fname) { - fclose(fout); - xfree(fout_name); - fout_name = NULL; - mkshort_del_handle(&gdb_short_handle); + fout = gbfopen_le(fname, "wb", MYNAME); + + gdb_category = (gdb_opt_category) ? atoi(gdb_opt_category) : 0; + gdb_ver = (gdb_opt_ver && *gdb_opt_ver) ? atoi(gdb_opt_ver) : 0; + + if (gdb_ver >= GDB_VER_UTF8) + cet_convert_init(CET_CHARSET_UTF8, 1); + + QUEUE_INIT(&wayptq_out); + short_h = NULL; + + waypt_ct = 0; + waypth_ct = 0; + rtept_ct = 0; + trkpt_ct = 0; + rte_ct = 0; + trk_ct = 0; } -static void -gdb_read(void) +static void +done_writer(void) { - gdb_read_data(); + disp_summary(fout); + gdb_flush_waypt_queue(&wayptq_out); + mkshort_del_handle(&short_h); + gbfclose(fout); } static void -gdb_write(void) +write_data(void) { - gdb_write_file_header(); - gdb_write_data(); + if (gdb_opt_ver) gdb_ver = atoi(gdb_opt_ver); + write_header(); + + reset_short_handle("WPT"); + route_flag = 0; + waypt_disp_all(write_waypoint_cb); + route_flag = 1; + route_disp_all(NULL, NULL, write_waypoint_cb); + + reset_short_handle("Route"); + route_disp_all(write_route_cb, NULL, NULL); + + reset_short_handle("Track"); + track_disp_all(write_track_cb, NULL, NULL); + + FWRITE_i32(2); /* finalize gdb with empty map segment */ + FWRITE_CSTR("V"); + FWRITE_C(1); } /*******************************************************************************/ +#define GDB_OPT_VER "ver" +#define GDB_OPT_VIA "via" +#define GDB_OPT_CATEGORY "cat" +#define GDB_OPT_ROADBOOK "roadbook" + +static arglist_t gdb_args[] = { + {GDB_OPT_CATEGORY, &gdb_opt_category, + "Default category on output (1..16)", + NULL, ARGTYPE_INT, "1", "16"}, + {GDB_OPT_VER, &gdb_opt_ver, + "Version of gdb file to generate (1..3)", + "2", ARGTYPE_INT, "1", "3"}, + {GDB_OPT_VIA, &gdb_opt_via, + "Drop route points that do not have an equivalent waypoint (hidden points)", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + {GDB_OPT_ROADBOOK, &gdb_opt_roadbook, + "Include major turn points (with description) from calculated route", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + ARG_TERMINATOR +}; + ff_vecs_t gdb_vecs = { ff_type_file, FF_CAP_RW_ALL, - gdb_rd_init, - gdb_wr_init, - gdb_rd_deinit, - gdb_wr_deinit, - gdb_read, - gdb_write, + init_reader, + init_writer, + done_reader, + done_writer, + read_data, + write_data, NULL, gdb_args, CET_CHARSET_MS_ANSI, 0 /* O.K.: changed to NON-FIXED */ diff --git a/xmldoc/formats/options/gdb-roadbook.xml b/xmldoc/formats/options/gdb-roadbook.xml new file mode 100644 index 000000000..76ac5ddf8 --- /dev/null +++ b/xmldoc/formats/options/gdb-roadbook.xml @@ -0,0 +1,19 @@ + + If this option is specified, GPSBabel drops all calculated route points, + with exception of points with a description (i.e. "Make U-turns until you know where you are."). + The priority of this option is higher than of the option. + A value of 1 or y overwrites the settings. + + + Using gdb option <option>roadbook</option> to create simple html roadbook + + + gpsbabel -i gdb,roadbook -f sample.gdb -x nuketypes,waypoints,tracks -x transform,wpt=rte -o html -F roadbook.html + + + + Because gdb creates internal a route AND a waypoint list, you have to drop all + waypoints and transform the route into waypoints. So you'll get a well ordered + html output. We sugess these steps for all waypoint-only formats as html. + + -- 2.30.2